package world;

public class Chunk {
	/*
	 * Author: William Stern
	 * Class: CS680
	 * 
	 * Chunk structure currently based on the chunk described at https://sites.google.com/site/voxelenginelwjglport/03-setting-up-a-chunk
	 
		
	 */
	static final int BLOCKS_PER_CUBIC_CHUNK=16;
	public static int getBlocksPerCubicChunk() {
		return BLOCKS_PER_CUBIC_CHUNK;
	}
	protected Block blocks[][][];
	private boolean loaded=false;
	private boolean setup=false;
	private boolean visible=false;
	private boolean waitingToBeRendered=false;
	private boolean isRendered=false;
	
	//Position of the chunk
	private int[] xyz={0,0,0};
	
	public Chunk()
	{
		
		//initChunk(BlockElement.Element_Dirt);// initialize world array
		
	}//end Chunk()
	public Chunk(BlockElement element, int x, int y, int z)
	{
		initChunk( element,x,y,z);//init the chunk with the element passed to it
	}
	public Chunk(int x, int y, int z)
	{
		
	}
	
	
	public void setUpChunk()
	{
		initChunk(BlockElement.Element_Dirt,0,0,0);// initialize world array with basic 
	}//sets up a chunk
	
	public void setUpChunk(int x, int y, int z)
	{
		
		initChunk(BlockElement.Element_Dirt,x,y,z);// initialize world array with basic 
		
	}
	
	public void setUpChunk(BlockElement element,int x, int y, int z)
	{
		initChunk(element,x,y,z);// initialize world array with basic 
		
	}
	
	public void setUpChunk(boolean[][][] visibilityList, BlockElement[][][] elements)
	{
		if(visibilityList.length==BLOCKS_PER_CUBIC_CHUNK&&elements.length==BLOCKS_PER_CUBIC_CHUNK)
		{
			for(int l1 = 0; l1< BLOCKS_PER_CUBIC_CHUNK; l1 ++){
				if(visibilityList[l1].length==BLOCKS_PER_CUBIC_CHUNK&&elements[l1].length==BLOCKS_PER_CUBIC_CHUNK)
				{
					for (int l2 =0; l2<BLOCKS_PER_CUBIC_CHUNK; l2++)
					{
						if(visibilityList[l2].length==BLOCKS_PER_CUBIC_CHUNK&&elements[l2].length==BLOCKS_PER_CUBIC_CHUNK)
						{
						
							for (int l3 =0; l3<BLOCKS_PER_CUBIC_CHUNK; l3++)
							{
						
								blocks[l1][l2][l3].SetExistance(visibilityList[l1][l2][l3]);
				
							}
						
						}else
						{
							System.err.println("Error in setUpChunk. list wrong size in l3");
							System.exit(-1);
						}
					}
				}
				else
				{
					System.err.println("Error in setUpChunk. list wrong size in l2");
					System.exit(-1);
				}
			}
		}//
		else{
			System.err.println("Error in setUpChunk. list wrong size in l1");//state error message about incorrect size array passed
			System.exit(-1);//exit program
		}
		
	}// end setup
	
	private void initChunk(BlockElement element, int x, int y, int z)
	{
		
		//initialize world array to be equal to the blocks per cubic chunk
		blocks= new Block[BLOCKS_PER_CUBIC_CHUNK][BLOCKS_PER_CUBIC_CHUNK][BLOCKS_PER_CUBIC_CHUNK];
		
		xyz= new int[]{x,y,z};
		
		
		for(int l1 = 0; l1< BLOCKS_PER_CUBIC_CHUNK; l1 ++){
			
			for (int l2 =0; l2<BLOCKS_PER_CUBIC_CHUNK; l2++)
			{
				for (int l3 =0; l3<BLOCKS_PER_CUBIC_CHUNK; l3++)
				{
				// initialize each block in the loop.	
					blocks[l1][l2][l3] = new Block(element);
					//blocks[l1][l2][l3].SetExistance(true);
					
				}// end of for loop 3
				
			}// end of for loop 2
			
		}// end of for loop 1
	
	}//
	public void setBlockTypeHorizontally(BlockElement element, int start)
	{
		/*
		 * element is the kind of block to change to
		 * start is the height is where the change starts. start must be less than or equal to 15.
		 */
		for(int x = 0; x<BLOCKS_PER_CUBIC_CHUNK;x++){
			
			for(int y = start; y<BLOCKS_PER_CUBIC_CHUNK;y++)
			{
				for(int z = 0; z<BLOCKS_PER_CUBIC_CHUNK; z++)
				{
					blocks[x][y][z].setBlockType(element);
					
				}
			}//end y
		}//end x
	}
	
	public void setBlockTypeVerticallyOnX(BlockElement element, int start)
	{
		/*
		 * element is the kind of block to change to
		 * start is the height is where the change starts. start must be less than or equal to 15.
		 */
		for(int x = start; x<BLOCKS_PER_CUBIC_CHUNK;x++){
			for(int y = 0; y<BLOCKS_PER_CUBIC_CHUNK;y++)
			{
				for(int z = 0; z<BLOCKS_PER_CUBIC_CHUNK; z++)
				{
					blocks[x][y][z].setBlockType(element);
				}
			}//end y
		}//end x
	}
	public void setBlockTypeVerticallyOnZ(BlockElement element, int start)
	{
		/*
		 * element is the kind of block to change to
		 * start is the height is where the change starts. start must be less than or equal to 15.
		 */
		for(int x = 0; x<BLOCKS_PER_CUBIC_CHUNK;x++){
			
			for(int y = 0; y<BLOCKS_PER_CUBIC_CHUNK;y++)
			{
				for(int z = start; z<BLOCKS_PER_CUBIC_CHUNK; z++)
				{
					blocks[x][y][z].setBlockType(element);
				}
			}//end y
		}//end x
	}
	
	public void setAllBlockTypes(BlockElement element)
	{
		for(int l1 = 0; l1< BLOCKS_PER_CUBIC_CHUNK; l1 ++){
			
			for (int l2 =0; l2<BLOCKS_PER_CUBIC_CHUNK; l2++)
			{
				for (int l3 =0; l3<BLOCKS_PER_CUBIC_CHUNK; l3++)
				{
				// initialize each block in the loop.	
					try {
						
						blocks[l1][l2][l3].setBlockType(element);
						
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						
						//System.err.println("l1: "+l1+" l2: "+l2+l1+" l3: "+l3+"");
						//System.err.println("Block per cubic chunk "+BLOCKS_PER_CUBIC_CHUNK);
						
					}
					
				}// end of for loop 3
				
			}// end of for loop 2
			
		}// end of for loop 1
	}
	
	public void updateBlockState(int x, int y, int z, boolean state)
	{
		
		blocks[x][y][z].SetExistance(state);
		
	}//change a blocks state
	public void changeBlockType(int x, int y, int z,BlockElement type)
	{
		blocks[x][y][z].setBlockType(type);
	}
	
	public Block[][][] renderChunk()
	{
		
		return blocks;
		
	}
	
	public int getNumberOfExistingBlocks()
	{
		int exist=0;
		for(int x=0;x<blocks.length;x++)
		{
			for(int y=0;y<blocks.length;y++)
			{
				for(int z=0; z<blocks.length;z++)
				{
					
					if(blocks[x][y][z].exists())
					{
						exist++;
					}
					
				}
				
				
			}
		}
		
		return exist;
	}
	/**
	 * @return the xyz
	 */
	public int[] getXyz() {
		return xyz;
	}
	/**
	 * @param xyz the xyz to set
	 */
	public void setXyz(int[] xyz) {
		this.xyz = xyz;
	}
	
	public boolean isLoaded() {
		return loaded;
	}
	public void setLoaded(boolean loaded) {
		this.loaded = loaded;
	}
	/**
	 * @return the setup
	 */
	public boolean isSetup() {
		return setup;
	}
	/**
	 * @param setup the setup to set
	 */
	public void setSetup(boolean setup) {
		this.setup = setup;
	}
	/**
	 * @return the visible
	 */
	public boolean isVisible() {
		return visible;
	}
	/**
	 * @param visible the visible to set
	 */
	public void setVisible(boolean visible) {
		this.visible = visible;
	}
	/**
	 * @return the render
	 */
	public boolean isWaitingToBeRendered() {
		return waitingToBeRendered;
	}
	/**
	 * @param render the render to set
	 */
	public void setWaitingToBeRendered(boolean render) {
		this.waitingToBeRendered = render;
	}
	/**
	 * @return the isRendered
	 */
	public boolean isRendered() {
		return isRendered;
	}
	/**
	 * @param isRendered the isRendered to set
	 */
	public void setRendered(boolean isRendered) {
		this.isRendered = isRendered;
	}
}
